package com.liziguo.lzgfp.server.netty.handler;

import com.liziguo.lzgfp.system.codec.AESCodec;
import com.liziguo.lzgfp.system.codec.JSONObjectCodec;
import com.liziguo.lzgfp.system.util.AESUtil;
import com.liziguo.lzgfp.system.util.RSAUtil;
import com.liziguo.lzgfp.system.util.RanStrUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * @Author: Liziguo
 * @Date: 2021/12/27 14:53
 */
public class SecurityHandler extends SimpleChannelInboundHandler<String> {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private RSAUtil.RSAKey rsaKey;

    private String aesKey;

    //第几次读到数据
    private int index;

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //30秒之后如果还没完成RSA验证 则断开连接
        ctx.channel().eventLoop().schedule(() -> {
            if (ctx.pipeline().get(SecurityHandler.class) != null) {
                ctx.close();
                logger.debug("断开了一个未能完成RSA的连接{}", ctx.channel().remoteAddress());
            }
        }, 30, TimeUnit.SECONDS);
        rsaKey = RSAUtil.genKey();
        logger.debug("服务器生成RSA密钥:{}", rsaKey);
        ctx.channel().writeAndFlush(rsaKey.publickey());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
        switch (index++) {
            case 0 -> {
                String clientPublicKey = RSAUtil.decrypt(s, rsaKey.privatekey());
                logger.debug("客户端公钥:{}", clientPublicKey);
                aesKey = RanStrUtil.ranStr(40);
                logger.debug("生成AES密钥:{}", aesKey);
                ctx.channel().writeAndFlush(RSAUtil.encrypt(aesKey, clientPublicKey));
            }
            case 1 -> {
                String msg = AESUtil.decryptToString(s, aesKey);
                logger.debug("使用AES密钥解密客户端发送过来的消息成功:{}", msg);
                ctx.pipeline().remove(this);
                ctx.pipeline().remove(StringEncoder.class);
                ctx.pipeline().remove(StringDecoder.class);
                //添加心跳监听
                ctx.pipeline().addFirst(new IdleStateHandler(120, 60, 0));
                //添加AES编解码器
                ctx.pipeline().addLast(new AESCodec(aesKey));
                ctx.pipeline().addLast(new StringEncoder());
                ctx.pipeline().addLast(new StringDecoder());
                //添加JSON编解码器
                ctx.pipeline().addLast(new JSONObjectCodec());
                //添加业务Handler
                ctx.pipeline().addLast(new ServerHandler(aesKey));
            }
            default -> ctx.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error(cause.getMessage());
        cause.printStackTrace();
        ctx.close();
    }
}
